/*
 *  Brno University of Technology
 *
 *  Copyright (C) 2009-2010 by Brno University of Technology and the contributors
 *
 *  Complete list of developers available at our web site:
 *
 *       http://spl.utko.feec.vutbr.cz
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
 */
package cz.vutbr.feec.utko.ef.ga;

import org.apache.log4j.Logger;

import cz.vutbr.feec.utko.ef.core.Random;

/**
 * The Class GeneticAlgorithmGen represents a single gene in genetic programming
 * chromozome.
 */
public class GAGene {

	/** The log. */
	transient private static Logger log = Logger.getLogger(GAGene.class);

	/** The minimum value. */
	private Double minValue;

	/** The maximum value. */
	private Double maxValue;

	/** The data. */
	private Double data;

	/** The data type. */
	private AttributeTypeEnum dataType;

	/**
	 * Gets the data type.
	 * 
	 * @return the data type
	 */
	public AttributeTypeEnum getDataType() {
		return dataType;
	}

	/**
	 * Sets the data type.
	 * 
	 * @param dataType the new data type
	 */
	public void setDataType(AttributeTypeEnum dataType) {
		this.dataType = dataType;
	}

	/**
	 * Instantiates a new gA gene.
	 */
	public GAGene() {

	}

	/**
	 * Instantiates a new gA gene.
	 * 
	 * @param minValue the min value
	 * @param maxValue the max value
	 * @param dataType the data type
	 */
	public GAGene(Double minValue, Double maxValue, AttributeTypeEnum dataType) {
		this.minValue = minValue;
		this.maxValue = maxValue;
		this.dataType = dataType;
		randomInit();
	}

	/**
	 * Instantiates a new genetic algorithm gen.
	 * 
	 * @param minValue
	 *            the minimum value
	 * @param maxValue
	 *            the maximum value
	 * @param data
	 *            the data
	 * @param dataType
	 *            the data type
	 */
	public GAGene(Double minValue, Double maxValue, Double data,
			AttributeTypeEnum dataType) {
		this.minValue = minValue;
		this.maxValue = maxValue;
		this.data = data;
		this.dataType = dataType;
	}

	/**
	 * Clone deep.
	 * 
	 * @return the gA gene
	 */
	public GAGene cloneDeep() {
		GAGene newGene = new GAGene();
		newGene.data = data;
		newGene.dataType = dataType;
		newGene.maxValue = maxValue;
		newGene.minValue = minValue;
		return newGene;
	}

	/**
	 * Gets the attribute type.
	 * 
	 * @return the attribute type
	 */
	public AttributeTypeEnum getAttributeType() {
		return this.dataType;
	}

	/**
	 * Gets the data.
	 * 
	 * @return the data
	 */
	public Double getData() {
		return this.data;
	}

	/**
	 * Gets the maximum value.
	 * 
	 * @return the maximum value
	 */
	public Double getMaxValue() {
		return this.maxValue;
	}

	/**
	 * Gets the minimum value.
	 * 
	 * @return the minimum value
	 */
	public Double getMinValue() {
		return this.minValue;
	}

	/**
	 * Random initialization gene at index i.
	 * 
	 * @param geneIndex
	 *            is the index number to be (re)initialized with the number in
	 *            range of constraints.
	 */
	public void randomInit() {
		Random rnd = new Random();
		switch (this.getAttributeType()) {
		case Boolean:
			if (this.getData() < 0.5) {
				this.setData(1.0);
			} else {
				this.setData(0.0);
			}
			break;

		case Double:
			this.setData(this.getMinValue() + rnd.nextDouble()
					* (this.getMaxValue() - this.getMinValue()));
			break;

		case Integer:
			this.setData(Math.floor(this.getMinValue() + rnd.nextDouble()
					* (this.getMaxValue() - this.getMinValue())));
			break;

		default:
			log.error("The type for mutation is unknown!");
			throw new RuntimeException("Undefined type of GA gene!");
		}
	}

	/**
	 * Sets the attribute type.
	 * 
	 * @param attributeType
	 *            the new attribute type
	 */
	public void setAttributeType(AttributeTypeEnum attributeType) {
		this.dataType = attributeType;
	}

	/**
	 * Sets the data.
	 * 
	 * @param data
	 *            the new data
	 */
	public void setData(Double data) {
		this.data = data;
	}

	/**
	 * Sets the maximum value.
	 * 
	 * @param maxValue
	 *            the new maximum value
	 */
	public void setMaxValue(Double maxValue) {
		this.maxValue = maxValue;
	}

	/**
	 * Sets the minimum value.
	 * 
	 * @param minValue
	 *            the new minimum value
	 */
	public void setMinValue(Double minValue) {
		this.minValue = minValue;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return ("Gen Hash : " + this.hashCode() + ", MinValue = "
				+ this.minValue + ", MaxValue = " + this.maxValue + ", Data = " + this.data);
	}
}
